/*
 * Date：10/23/18 10:15 PM
 * Author: guomw
 *
 */

package org.elanfox.intellicommunity.biz.service.core.equipment.impl;

import org.elanfox.intellicommunity.biz.dto.equipment.ConcealPointSaveDTO;
import org.elanfox.intellicommunity.biz.entity.equipment.ConcealPointPO;
import org.elanfox.intellicommunity.biz.entity.equipment.TrackPO;
import org.elanfox.intellicommunity.biz.repository.equipment.ConcealPointRepository;
import org.elanfox.intellicommunity.biz.service.core.equipment.ConcealPointService;
import org.elanfox.intellicommunity.biz.service.core.equipment.TrackService;
import org.elanfox.intellicommunity.biz.vo.ConcealPointVO;
import org.elanfox.intellicommunity.data.base.base.AbstractSearchableCrudService;
import org.elanfox.intellicommunity.data.base.base.SpecificationAndSort;
import org.elanfox.intellicommunity.data.base.dto.BaseSaveDTO;
import org.elanfox.intellicommunity.data.base.dto.BaseSearchDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;

/**
 * 定位器相关service
 *
 * @author loutianxi
 * @date 2019-12-05
 */
@Service
public class ConcealPointServiceImpl extends AbstractSearchableCrudService<ConcealPointPO, Integer> implements ConcealPointService {

    @Autowired
    private ConcealPointRepository repository;
    @Autowired
    private TrackService trackService;

    protected ConcealPointServiceImpl(ConcealPointRepository repository) {
        super(repository);
    }

    @Override
    protected SpecificationAndSort<ConcealPointPO> specificationAndSort(BaseSearchDTO condition) {
        Specification<ConcealPointPO> specification = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
        };

        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        return new SpecificationAndSort<>(specification, sort);
    }


    @Override
    public ConcealPointPO save(BaseSaveDTO saveDTO) {
        ConcealPointSaveDTO concealPointSaveDTO = (ConcealPointSaveDTO) saveDTO;
        ConcealPointPO concealPointPO = findById(concealPointSaveDTO.getId());
        //保存隐藏点
        if (concealPointPO == null) {
            concealPointPO = new ConcealPointPO();
        }
        concealPointPO.setLatitude(concealPointSaveDTO.getLatitude());
        concealPointPO.setLongitude(concealPointSaveDTO.getLongitude());
        concealPointPO.setStructureId(concealPointSaveDTO.getStructureId());
        concealPointPO = save(concealPointPO);
        //保存轨迹
        saveTrack(concealPointSaveDTO, concealPointPO);
        return concealPointPO;
    }

    private void saveTrack(ConcealPointSaveDTO saveDTO, ConcealPointPO concealPointPO) {
        //保存轨迹
        TrackPO trackPO = new TrackPO();
        trackPO.setStartPoint(saveDTO.getStartPoint());
        trackPO.setEndPoint(saveDTO.getEndPoint());
        trackPO.setLastPoint(saveDTO.getLastPoint());
        trackPO.setNextPoint(saveDTO.getNextPoint());
        trackPO.setPoint(concealPointPO);
        trackService.save(trackPO);
        //搜索轨迹中的上一个隐藏点
        if (saveDTO.getLastPoint() != null) {
            TrackPO lastTrack = trackService.find(saveDTO.getStartPoint(), saveDTO.getEndPoint(), saveDTO.getLastPoint());
            if (lastTrack == null) {
                throw new IllegalStateException("上一个隐藏点不存在");
            }
            lastTrack.setNextPoint(concealPointPO.getId());
            trackService.save(lastTrack);
        }
        //搜索轨迹中的下一个隐藏点
        if (saveDTO.getNextPoint() != null) {
            TrackPO nextTrack = trackService.find(saveDTO.getStartPoint(), saveDTO.getEndPoint(), saveDTO.getNextPoint());
            if (nextTrack == null) {
                throw new IllegalStateException("下一个隐藏点不存在");
            }
            nextTrack.setLastPoint(concealPointPO.getId());
            trackService.save(nextTrack);
        }
    }

    @Override
    public List<ConcealPointVO> findByStrId(Integer strId) {
        List<ConcealPointVO> voList = new ArrayList<>();
        List<ConcealPointPO> list = repository.findByStructureId(strId);
        for (ConcealPointPO po : list) {
            ConcealPointVO vo = new ConcealPointVO();
            vo.setId(po.getId());
            vo.setLatitude(po.getLatitude());
            vo.setLongitude(po.getLongitude());
            TrackPO trackPO = trackService.findByPointId(po.getId());
            vo.setStartPoint(trackPO.getStartPoint());
            vo.setEndPoint(trackPO.getEndPoint());
            vo.setLastPoint(trackPO.getLastPoint());
            vo.setNextPoint(trackPO.getNextPoint());
            voList.add(vo);
        }
        return voList;
    }

    @Override
    public ConcealPointPO update(ConcealPointSaveDTO dto) {
        ConcealPointPO concealPointPO = findById(dto.getId());
        if (concealPointPO == null) {
            return null;
        }
        concealPointPO.setLongitude(dto.getLongitude());
        concealPointPO.setLatitude(dto.getLatitude());
        return save(concealPointPO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(Integer id) {
        //第二步删除轨迹
        TrackPO trackPO = trackService.findByPointId(id);
        trackService.deleteByPointId(id);
        //第一步删除隐藏点
        repository.deleteById(id);
        //第三步重新连接隐藏点
        if (trackPO.getLastPoint() != null) {
            TrackPO lastTrack = trackService.findByPointId(trackPO.getLastPoint());
            lastTrack.setNextPoint(trackPO.getNextPoint());
            trackService.save(lastTrack);
        }
        if (trackPO.getNextPoint() != null) {
            TrackPO nextTrack = trackService.findByPointId(trackPO.getNextPoint());
            nextTrack.setLastPoint(trackPO.getLastPoint());
            trackService.save(nextTrack);
        }
        return true;
    }
}
